package com.lecture.junit.tdd.example;

import java.util.Calendar;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import com.lecture.junit.tdd.exceptions.*;

public abstract class LoginServiceState {

    private static final int MAX_TIME_BEFORE_PASSWORD_EXPIRED = 30;
	private static final int MAX_TIME_BEFORE_LAST_USED_EXPIRED = 45;
	AtomicInteger count;
    AtomicLong timeStamp;

    public void login(LoginServiceInterface context, IAccount acc, String password) {
        if (acc.passwordMatches(password)) {
            if (acc.isLoggedIn()) {
                throw new AccountAlreadyLoggedInException();
            }
            if (acc.isRevoked()) {
                throw  new AccountIsRevokedException();
            }
            if(isPasswordExpired(acc)) {
            	throw new PasswordExpiredException();
            }
            if(isLastUsedTimeExpired(acc)) {
            	acc.setRevoked();
            	throw new AccountNotUsedException();    		
            }

            acc.setLoggedIn();
            setTimeStamp();
            context.setState(acc.getUserName(), new AwaitFirstLoginAttempt());
        
        } else {
            handlePasswordFail(context, acc);
        }
    }

	
	public void setCount(AtomicInteger count) {
		this.count = count;
	}

	public AtomicInteger getCount() {
		return count;
	}
	
	public void setTimeStamp() {
		this.timeStamp = new AtomicLong(System.currentTimeMillis());
	}
	
    public boolean isPasswordExpired(IAccount acc) {
        Calendar date = Calendar.getInstance();
        date.add(Calendar.DAY_OF_YEAR, -MAX_TIME_BEFORE_PASSWORD_EXPIRED);
        return date.after(acc.getPasswordSetDate()) ? true : false;
    }
    
    public boolean isLastUsedTimeExpired(IAccount acc) {
        Calendar date = Calendar.getInstance();
        date.add(Calendar.DAY_OF_YEAR, -MAX_TIME_BEFORE_LAST_USED_EXPIRED);
        return date.after(acc.getLastUseDate()) ? true : false;
    }

	public void changePassword(LoginServiceInterface context, IAccount acc, 
			String oldPassword, String newPassword) {
		
		if(!acc.passwordMatches(oldPassword)) {
			throw new IncorrectPasswordException();
		} else if(acc.isNewPasswordAlreadyUsed(newPassword)) {
			throw new IncorrectNewPasswordException();
		} else {
			acc.setPassword(newPassword);
		}
	}

	protected abstract void handlePasswordFail(LoginServiceInterface context, IAccount acc);
	
	
}
